package sim.models;

import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.app.Application;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.input.controls.ActionListener;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import sim.dynamics.IModelMotion;

/**
 *
 * @author Ahmed Abdelkader
 */
public abstract class BaseModel implements ActionListener, PhysicsCollisionListener, AnimEventListener {
    protected Application app;
    protected Node model;
    CharacterControl character;
    protected IModelMotion motion;
    AnimControl animationControl;
    AnimChannel animationChannel;
    
    public BaseModel(Application app, String modelPath) {
        this.app = app;
        initCharacter(modelPath);
        setupAnimationController();
    }

    /*
     * Load the spatial and apply initial transformations.
     */
    private void initCharacter(String modelPath) {
        model = (Node) app.getAssetManager().loadModel(modelPath);
        model.setLocalScale(getScale());
        model.setLocalRotation(getZeroRotation());
        model.setLocalTranslation(getOffset());
        
        BoxCollisionShape cBox = new BoxCollisionShape(new Vector3f(20f, 100f, 20f));
        character = new CharacterControl(cBox, 10f);
        character.setJumpSpeed(20);
        character.setFallSpeed(30);
        character.setGravity(30);
        model.addControl(character);
    }
    
    private void setupAnimationController() {
        animationControl = model.getControl(AnimControl.class);
        animationControl.addListener(this);
        animationChannel = animationControl.createChannel();
    }

    public void lookAt(Vector3f dir) {
        character.setViewDirection(dir);
    }
    
    public Node getModel() {
        return model;
    }
    
    public CharacterControl getControl() {
        return character;
    }

    public void move() {
        this.motion.move(this);
    }

    public void walk(Vector3f offest) {
        character.setWalkDirection(offest);
    }

    public boolean contains(Geometry g) {
        return model.hasChild(g);
    }

    public void setMotion(IModelMotion motion) {
        this.motion = motion;
    }

    public Vector3f getLocalTranslation() {
        return character.getPhysicsLocation();
    }

    public void setLocalTranslation(float x, float y, float z) {
        character.setPhysicsLocation(new Vector3f(x, y, z));
    }

    /*
     * Returns the direction to which the model is facing towards.
     */
    public Vector3f getDirection() {
        return character.getViewDirection();
    }

    /*
     * A suitable scale for initially large/small models.
     */
    protected float getScale() {
        return 1.0f;
    }

    /*
     * Models should start at the origin.
     */
    protected Vector3f getOffset() {
        return Vector3f.ZERO;
    }

    /*
     * Models should start facing X with Y to the left and Z up.
     */
    protected Quaternion getZeroRotation() {
        return Quaternion.IDENTITY;
    }

    public void onAction(String binding, boolean value, float tpf) {
    }

    public void collision(PhysicsCollisionEvent event) {
        System.out.println(event.getNodeA().getName() + " <> " +
                event.getNodeB().getName());
    }

    public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
    }

    public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
    }
}
